//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <linknode.h>
#include <elapi.h>
#include <prxstub.h>
#include <_critsec.h>
#include <eladef.h>
#include <bootmods.h>
#include <stdlib.h>
#include <string.h>
#include <elacfg.h>
#include <ctype.h>
#include "CCallbackContext.h"
#include <pseudo.h>
#include <elacs.h>

#ifdef _MSVC
#pragma warning(disable: 4190)
#endif

IProcess * g_pICurProcess;
CriticalSection g_moduleLock;
CriticalSection g_tlsLock;
CriticalSection g_staticObjectListLock;
CriticalSection g_processExitRoutineListLock;
Byte g_tlsTypes[TLS_TOTAL_SLOTS];
DLinkNode g_tlsAllocatedList;
DLinkNode g_tlsAllocatedNodes[TLS_TOTAL_SLOTS];
EXTERN_C const InterfaceID EIID_IProxy;
PInterface g_pMainCallbackContext = NULL;

EXTERN void CleanUpThreadLocalSlots();
static void CleanUpAllThreadsLocalSlots();

void FreeCurProcComponents();
EXTERN_C void  _GetEnvBase(wchar_t ***, wchar_t **);

UInt32 s_uDelayLoopCount = 0;

ELAPI_(void) _Elastos_SequencedContext_Enter(
        /* [in] */ void *pContext)
{
    if (NULL != pContext) {
        _CCriticalSection_Enter((CRITICAL_SECTION *)pContext);
        _CThread_SetLocalValue(TL_SEQUENCED_SLOT, pContext);
    }
}

ELAPI_(void *) _Elastos_SequencedContext_Leave()
{
    CRITICAL_SECTION *pLock;
    _CThread_GetLocalValue(TL_SEQUENCED_SLOT, (TLValue *)&pLock);
    if (NULL != pLock) {
        _CThread_SetLocalValue(TL_SEQUENCED_SLOT, NULL);
        _CCriticalSection_Leave(pLock);
    }
    return pLock;
}

struct ThreadQuitRoutineNode : public SLinkNode {
    ThreadQuitRoutineNode(void * pThis, void * pFunc) :
        m_delegate(EventHandler::Make(pThis, pFunc)) {}

    EventHandler m_delegate;
};

struct ProcessExitRoutineNode : public SLinkNode {
    ProcessExitRoutineNode(void * pThis, void * pFunc) :
        m_delegate(EventHandler::Make(pThis, pFunc)) {}

    EventHandler m_delegate;
};

class CThreadQuitContext : public IInterface
{
public:
    CARAPI_(PInterface) Probe(REIID riid)
    {
        return NULL;
    }

    CARAPI_(UInt32) AddRef()
    {
        return m_ref.Increment();
    }

    CARAPI_(UInt32) Release()
    {
        Int32 ref = m_ref.Decrement();
        if (ref == 0) {
            delete this;
        }
        return ref;
    }

    CARAPI Aggregate(AggrType aggrType, PInterface pObject)
    {
        return E_NOT_IMPLEMENTED;
    }

    CARAPI GetDomain(PInterface *ppObj)
    {
        return E_NOT_IMPLEMENTED;
    }

    CThreadQuitContext()
    {
        m_quitRoutineList.Initialize();
        m_staticObjectList.Initialize();
    }

    virtual ~CThreadQuitContext()
    {
        // Delete the thread quit routine nodes
        register SLinkNode * pNode = m_quitRoutineList.First();
        while (pNode != &m_quitRoutineList) {
            pNode->Detach(&m_quitRoutineList);
            delete pNode;
            pNode = m_quitRoutineList.First();
        }

        // Clean up thread static objects
        pNode = m_staticObjectList.First();
        while (pNode != &m_staticObjectList) {
            pNode->Detach(&m_staticObjectList);
            delete (StaticObject *)pNode;
            pNode = m_staticObjectList.First();
        }
    }

    void DoAtQuit()
    {
        // Call thread quit routines and delete the routine nodes
        void * pThis, * pFunc;
        register SLinkNode * pNode = m_quitRoutineList.First();
        while (pNode != &m_quitRoutineList) {
            pThis = ((ThreadQuitRoutineNode *)pNode)->m_delegate.GetThisPtr();
            pFunc = ((ThreadQuitRoutineNode *)pNode)->m_delegate.GetFuncPtr();
            pNode->Detach(&m_quitRoutineList);
            delete pNode;

            ((PThreadQuitRoutine)pFunc)(pThis);

            pNode = m_quitRoutineList.First();
        }

        // Clean up thread static objects
        pNode = m_staticObjectList.First();
        while (pNode != &m_staticObjectList) {
            pNode->Detach(&m_staticObjectList);
            delete (StaticObject *)pNode;
            pNode = m_staticObjectList.First();
        }
    }

    ECode AddQuitRoutine(PThreadQuitRoutine pEntry, PVoid pUserData)
    {
        assert(pEntry);
        ThreadQuitRoutineNode * pNode = new ThreadQuitRoutineNode(
                pUserData, *(void **)&pEntry);
        if (!pNode) return E_OUT_OF_MEMORY;
        m_quitRoutineList.InsertFirst(pNode);
        return NOERROR;
    }

    ECode AddObject(PInterface pObject)
    {
        assert(pObject);
        StaticObject * pNode = new StaticObject(pObject);
        if (!pNode) return E_OUT_OF_MEMORY;
        m_staticObjectList.InsertNext(pNode);
        return NOERROR;
    }

private:
    SLinkNode m_quitRoutineList;
    SLinkNode m_staticObjectList;
    Interlocked m_ref;
};

class CProcessExitContext
{
public:
    CProcessExitContext()
    {
        m_exitRoutineList.Initialize();
        m_staticObjectList.Initialize();
    }

    ~CProcessExitContext()
    {
      //  assert(m_exitRoutineList.IsEmpty() && m_staticObjectList.IsEmpty());
    }

    void DoAtExit()
    {
        // Call process exit routines and delete the routine nodes
        _CCriticalSection_Enter(&g_processExitRoutineListLock);
        void * pThis, * pFunc;
        register SLinkNode * pNode = m_exitRoutineList.First();
        while (pNode != &m_exitRoutineList) {
            pThis = ((ProcessExitRoutineNode *)pNode)->m_delegate.GetThisPtr();
            pFunc = ((ProcessExitRoutineNode *)pNode)->m_delegate.GetFuncPtr();
            pNode->Detach(&m_exitRoutineList);
            delete pNode;
            _CCriticalSection_Leave(&g_processExitRoutineListLock);

            ((PProcessExitRoutine)pFunc)(pThis);

            _CCriticalSection_Enter(&g_processExitRoutineListLock);
            pNode = m_exitRoutineList.First();
        }
        _CCriticalSection_Leave(&g_processExitRoutineListLock);

        // Clean up process static objects
        _CCriticalSection_Enter(&g_staticObjectListLock);
        pNode = m_staticObjectList.First();
        while (pNode != &m_staticObjectList) {
            pNode->Detach(&m_staticObjectList);
            delete (StaticObject *)pNode;
            pNode = m_staticObjectList.First();
        }
        _CCriticalSection_Leave(&g_staticObjectListLock);
    }

    ECode AddExitRoutine(PProcessExitRoutine pEntry, PVoid pUserData)
    {
        assert(pEntry);
        ProcessExitRoutineNode * pNode = new ProcessExitRoutineNode(
                pUserData, *(void **)&pEntry);
        if (!pNode) return E_OUT_OF_MEMORY;

        _CCriticalSection_Enter(&g_processExitRoutineListLock);
        m_exitRoutineList.InsertFirst(pNode);
        _CCriticalSection_Leave(&g_processExitRoutineListLock);

        return NOERROR;
    }

    ECode AddObject(PInterface pObject)
    {
        assert(pObject);
        StaticObject * pNode = new StaticObject(pObject);
        if (!pNode) return E_OUT_OF_MEMORY;

        _CCriticalSection_Enter(&g_staticObjectListLock);
        m_staticObjectList.InsertNext(pNode);
        _CCriticalSection_Leave(&g_staticObjectListLock);

        return NOERROR;
    }

private:
    SLinkNode m_exitRoutineList;
    SLinkNode m_staticObjectList;
};

static CProcessExitContext s_processExitContext;

class CAppletContext : public IInterface {
public:
    CARAPI_(PInterface) Probe(REIID riid)
    {
        return NULL;
    }

    CARAPI_(UInt32) AddRef()
    {
        Int32 nRef = m_ref.Increment();

        return (UInt32)nRef;
    }

    CARAPI_(UInt32) Release()
    {
        Int32 nRef = m_ref.Decrement();
        if (nRef == 0) {
            delete this;
        }
        return nRef;
    }

    CARAPI Aggregate(AggrType aggrType, PInterface pObject)
    {
        return E_NOT_IMPLEMENTED;
    }

    CARAPI GetDomain(PInterface *ppObj)
    {
        return E_NOT_IMPLEMENTED;
    }

    CAppletContext():m_pApplet(NULL), m_bValid(TRUE), m_pThreadQuitContext(NULL)
    {
    }

    virtual ~CAppletContext()
    {
        m_bValid = FALSE;
        if (m_pApplet) {
            m_pApplet->Release();
        }
        if (m_pThreadQuitContext) {
            m_pThreadQuitContext->Release();
        }
    }

    ECode Initialize(IApplet* pApplet)
    {
        if (NULL == pApplet) return E_INVALID_ARGUMENT;
        if (m_pThreadQuitContext) return NOERROR;

        m_pThreadQuitContext = new CThreadQuitContext;
        if (!m_pThreadQuitContext) return E_OUT_OF_MEMORY;

        m_pThreadQuitContext->AddRef();

        pApplet->AddRef();
        m_pApplet = pApplet;

        return NOERROR;
    }

    ECode Uninitialize()
    {
        if (m_pThreadQuitContext) {
            m_pThreadQuitContext->DoAtQuit();
            m_pThreadQuitContext->Release();
            m_pThreadQuitContext = NULL;
        }
        return NOERROR;
    }

    ECode AddQuitRoutine(PThreadQuitRoutine pEntry, PVoid pUserData)
    {
        if (m_pThreadQuitContext) {
            return m_pThreadQuitContext->AddQuitRoutine(pEntry, pUserData);
        }
        return E_APPLET_ALREADY_FINISHED;
    }

    ECode AddObject(PInterface pObject)
    {
        if (m_pThreadQuitContext) {
            return m_pThreadQuitContext->AddObject(pObject);
        }
        return E_APPLET_ALREADY_FINISHED;
    }

    Boolean IsValid()
    {
        return m_bValid;
    }

public:
    IApplet* m_pApplet;
private:
    Interlocked m_ref;
    Boolean m_bValid;
    CThreadQuitContext* m_pThreadQuitContext;
};

ELAPI _Impl_CAppletContext_GetCurrent(PInterface* ppAppletContext)
{
    PInterface pAppletContext;

    if (ppAppletContext == NULL) return E_INVALID_ARGUMENT;

    ECode ec = _CThread_GetLocalObject(TL_APPLET_SLOT, &pAppletContext);
    if (FAILED(ec)) return ec;

    if (pAppletContext == NULL) return E_NOT_IN_ANY_APPLET;

    if (!((CAppletContext*)pAppletContext)->IsValid()) return E_APPLET_ALREADY_FINISHED;
    *ppAppletContext = pAppletContext;

    return NOERROR;
}

ELAPI _Impl_CAppletContext_Initialize(
    IApplet* pApplet)
{
    CAppletContext* pAppletContext = new CAppletContext;

    if (NULL == pAppletContext) return E_OUT_OF_MEMORY;

    ECode ec = ((CAppletContext*)pAppletContext)->Initialize(pApplet);
    if (FAILED(ec)) {
        delete pAppletContext;
        return ec;
    }

    pAppletContext->AddRef();
    ec = _CThread_SetLocalObject(TL_APPLET_SLOT, pAppletContext);
    if (FAILED(ec)) return ec;

    PInterface pCallbackContext = NULL;
    _Impl_CallbackSink_GetCallbackContext(&pCallbackContext);
    assert(pCallbackContext);
    ((CCallbackContext *)pCallbackContext)->m_Status = AppletStatus_Starting;

    _CThread_SetLocalObject(TL_ORG_CALLBACK_SLOT, pCallbackContext);

    return NOERROR;
}

ELAPI _Impl_CAppletContext_Uninitialize()
{
    PInterface pAppletContext = NULL;
    PInterface pCallbackContext = NULL;

    _Impl_CallbackSink_GetCallbackContext(&pCallbackContext);
    assert(pCallbackContext);
    ((CCallbackContext *)pCallbackContext)->m_Status = AppletStatus_Deceased;
    ((CCallbackContext *)pCallbackContext)->CancelAllCallbackEvents();
    pCallbackContext->Release();

    _CThread_SetLocalObject(TL_ORG_CALLBACK_SLOT, NULL);

    ECode ec = _Impl_CAppletContext_GetCurrent(&pAppletContext);
    if (FAILED(ec)) return ec;

    if (pAppletContext) pAppletContext->Release();
    else return NOERROR;

    ec = ((CAppletContext*)pAppletContext)->Uninitialize();
    if (FAILED(ec)) return ec;

    return NOERROR;
}

class CCallbackRendezvous : public ICallbackRendezvous
{
public:
    CARAPI_(PInterface) Probe(REIID riid);
    CARAPI_(UInt32) AddRef();
    CARAPI_(UInt32) Release();

    CARAPI Aggregate(AggregateType type, PInterface pObj)
        { return E_NOT_IMPLEMENTED; }

    CARAPI GetDomain(PInterface *ppObj)
        { return E_NOT_IMPLEMENTED; }

    CCallbackRendezvous(
        PInterface pCallbackContext,
        ICallbackSink* pCallbackSink,
        Int32 eventId,
        Boolean* pbEventFlag,
        Boolean bNewCallback) :
            m_pCallbackContext(pCallbackContext),
            m_pCallbackSink(pCallbackSink),
            m_EventId(eventId),
            m_pbEventFlag(pbEventFlag),
            m_bNewCallback(bNewCallback)
    {
        if (m_pCallbackSink) m_pCallbackSink->AddRef();
    }

    virtual ~CCallbackRendezvous();

    CARAPI Wait(
            /* in */ Millisecond32 msTimeout,
            /* out */ WaitResult *result);

    PInterface                  m_pCallbackContext;
    ICallbackSink*              m_pCallbackSink;
    Int32                       m_EventId;
    Boolean*                    m_pbEventFlag;
    Boolean                     m_bNewCallback;
private:
    Interlocked                 m_cRef;
};

UInt32 CCallbackRendezvous::AddRef()
{
    Int32 nRef = m_cRef.Increment();
    return (UInt32)nRef;
}

UInt32 CCallbackRendezvous::Release()
{
    Int32 nRef = m_cRef.Decrement();

    if (0 == nRef) {
        delete this;
    }

    return nRef;
}

PInterface CCallbackRendezvous::Probe(REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)this;
    }
    return NULL;
}

CCallbackRendezvous::~CCallbackRendezvous()
{
    if (m_pCallbackSink) {
        if (m_bNewCallback) {
            PInterface pOrgCtx;
            _CThread_GetLocalObject(TL_CALLBACK_SLOT, &pOrgCtx);
            if (m_pCallbackContext) m_pCallbackContext->AddRef();
            _CThread_SetLocalObject(TL_CALLBACK_SLOT, m_pCallbackContext);
            m_pCallbackSink->RemoveCallback(
                                            m_EventId, EventHandler::Make(NULL, NULL));
            _CThread_SetLocalObject(TL_CALLBACK_SLOT, pOrgCtx);
        }
        m_pCallbackSink->Release();
    }
    if (m_pCallbackContext) m_pCallbackContext->Release();
}

ECode CCallbackRendezvous::Wait(
    Millisecond32 msTimeOut,
    WaitResult *result)
{

    ECode ec = _Impl_CallbackSink_WaitForCallbackEvent(
                            m_pCallbackContext,
                            msTimeOut,
                            result,
                            m_pbEventFlag,
                            0);

    return ec;
}

ELAPI _Impl_CCallbackRendezvous_New(
        PInterface pCallbackContext,
        ICallbackSink* pCallbackSink,
        CallbackEventId eventId,
        Boolean* pbEventFlag,
        Boolean bNewCallback,
        ICallbackRendezvous** ppICallbackRendezvous)
{
    if (NULL == ppICallbackRendezvous) return E_INVALID_ARGUMENT;
    *ppICallbackRendezvous = new CCallbackRendezvous(
                                    pCallbackContext,
                                    pCallbackSink,
                                    eventId,
                                    pbEventFlag,
                                    bNewCallback);
    if (*ppICallbackRendezvous == NULL) return E_OUT_OF_MEMORY;
    (*ppICallbackRendezvous)->AddRef();

    return NOERROR;
}

ELAPI _CApplet_GetCurrent(PInterface* ppApplet)
{
    PInterface pAppletContext = NULL;
    PInterface pApplet;
    ECode ec = _Impl_CAppletContext_GetCurrent(&pAppletContext);
    if (FAILED(ec)) return ec;

    pAppletContext->Release();

    pApplet = ((CAppletContext*)pAppletContext)->m_pApplet;
    pApplet->AddRef();

    *ppApplet = pApplet;

    return NOERROR;
}

ELAPI _CApplet_AtFinish(
            PThreadQuitRoutine pEntry,
            PVoid pUserData)
{
    ECode ec;
    PInterface pAppletContext = NULL;
    if (!pEntry) return E_INVALID_ARGUMENT;

    ec = _Impl_CAppletContext_GetCurrent(&pAppletContext);
    if (FAILED(ec) && E_NOT_IN_ANY_APPLET != ec) return ec;

    if (pAppletContext) pAppletContext->Release();
    else return _CProcess_AtExit(pEntry, pUserData);

    return ((CAppletContext*)pAppletContext)->AddQuitRoutine(pEntry, pUserData);
}

ELAPI _CApplet_GetAllThreads(IObjectEnumerator** ppThreads)
{
    IApplet *pApplet;

    ECode ec = _CApplet_GetCurrent((PInterface *)&pApplet);
    if (FAILED(ec)) return ec;

    ec = pApplet->GetAllThreads(ppThreads);
    pApplet->Release();

    return ec;
}

static void ThreadEntry(PVoid * pArgs)
{
    ECode ec = NOERROR;

    ec = PseudoKernel_ThreadStartEntry(pArgs);

     _CThread_Quit(ec);

    assert(0);
    return;
}

// ElAPI functions
//

ELAPI _CSystem_RegisterRunningObject(
    WString name,
    PInterface pService)
{
    return CPseudoSyscall::RegisterRunningObject(name, pService);
}

EXTERN IDeviceDriver *g_pBootModulesDrv;

EXTERN ECode HackGrafixRunningObject(WString, PInterface*, Boolean*);
ELAPI _CSystem_FindRunningObject(
    WString name,
    PInterface *ppService)
{
    if (name.IsNull() || !ppService) {
        return E_INVALID_ARGUMENT;
    }

    if (!wcscmp(L"device:bootmods0", name)) {
        *ppService = g_pBootModulesDrv;
        g_pBootModulesDrv->AddRef();
        return NOERROR;
    }

    {
        Boolean bFiltered = FALSE;
        ECode ec = NOERROR;

        ec = HackGrafixRunningObject(name, ppService, &bFiltered);
        if (bFiltered) {
            return ec;
        }
    }

    return CPseudoSyscall::FindRunningObject(name, ppService);
}

ELAPI _CSystem_WaitForRunningObject(
    WString name,
    Int32 timeout,
    WaitResult *pResult)
{
    return CPseudoSyscall::WaitForRunningObject(name, timeout, pResult);
}

ELAPI _CSystem_UnregisterRunningObject(
    WString name)
{
    if (name.IsNull()) {
        return E_INVALID_ARGUMENT;
    }

    return CPseudoSyscall::UnregisterRunningObject(name);
}

ELAPI _CSystem_GetMachineTime(
    SystemTime *pSystemTime)
{
    return CPseudoKernel::System_GetTime(pSystemTime);
}

ELAPI _CSystem_SetMachineTime(
    SystemTime systemTime)
{
    return CPseudoKernel::System_SetTime(&systemTime);
}

ELAPI_(Millisecond32) _CSystem_GetElapsedTime()
{
    Millisecond32 ms;
    ECode ec = CPseudoKernel::System_GetElapsedTime(&ms);
    if (FAILED(ec)) {
        ms = -1;
    }
    return ms;
}

ELAPI_(Millisecond32) _CSystem_GetIdleTime()
{
    Millisecond32 ms;
    ECode ec = CPseudoKernel::System_GetIdleTime(&ms);
    if (FAILED(ec)) {
        ms = -1;
    }
    return ms;
}

ELAPI_(Int32) _CSystem_GetVersion()
{
    return ELASTOS_VERSION_HEX;
}

ELAPI _CSystem_GetGlobalMemorySizes(
    Int32 *pTotalPhysicalMemorySize,
    Int32 *pAvailablePhysicalMemorySize)
{
    return CPseudoKernel::System_GetMemorySizes(
                              pTotalPhysicalMemorySize,
                              pAvailablePhysicalMemorySize);
}

extern IDeviceDriver* g_pConsole;
extern bool g_bUsingConsoleChannel;

ECode PrintToConsoleDevice(const wchar_t * wstr)
{
    ECode ec;

    if (g_pConsole == NULL) {
        ec = _CSystem_FindRunningObject(L"device:console0",
            (PInterface *)&g_pConsole);
        if (FAILED(ec)) {
            return ec;
        }
    }

    uint32_t uLength = wcslen(wstr);
    if (0 == uLength) {
        return NOERROR;
    }

    Int32 len = sizeof(wchar_t) * uLength + 1;
    char *pas = (char *)_alloca(len);

    Int32 retlen = wcstombs(pas, wstr, len);
    if (retlen == -1) return E_NOT_SUPPORTED;

    MemoryBuf ezbbbContent((Byte*)pas, strlen(pas));
    Int32 nWritten = 0;
    ec = g_pConsole->Write(0, ezbbbContent, &nWritten, NULL);
    return ec;
}

ELAPI _CSystem_DebugPrint(
    WString string)
{
    if (string.IsNull()) return E_INVALID_ARGUMENT;
    if (g_bUsingConsoleChannel) {
        ECode ec = PrintToConsoleDevice(string);
        if (SUCCEEDED(ec)) {
        	return NOERROR;
        }
    }
    return CPseudoSyscall::SysPrint(string);
}

ELAPI _CSystem_DebugErrorPrint(
    WString string)
{
    if (string.IsNull()) return E_INVALID_ARGUMENT;
    if (g_bUsingConsoleChannel) {
        ECode ec = PrintToConsoleDevice(string);
        if (SUCCEEDED(ec)) {
        	return NOERROR;
        }
    }
    return CPseudoSyscall::SysErrorPrint(string);
}

ELAPI _EzGetVirKey(
    struct KBDStatus *pVirtualCode)
{
    return CPseudoSyscall::SysGetVirtualCode(pVirtualCode);
}

ELAPI _CSystem_Reboot()
{
    return CPseudoKernel::System_Reboot();
}

ELAPI _CSystem_QueryPerformanceCounter(
        _ELASTOS Int64 *pPerformanceCount)
{
    return CPseudoKernel::System_QueryPerformanceCounter(pPerformanceCount);
}

ELAPI _CSystem_QueryPerformanceFrequency(
        _ELASTOS Int64 *pFrequency)
{
    return CPseudoKernel::System_QueryPerformanceFrequency(pFrequency);
}

ELAPI _CProcess_NewUnstarted(
    IProcess **ppProcess)
{
    return CPseudoKernel::Process_CreateWithUnstarted(ppProcess);
}

ELAPI _CProcess_New(
    WString name,
    WString args,
    IProcess **ppProcess)
{
    ECode ec = NOERROR;
    IProcess *pIProcess;

    ec = CPseudoKernel::Process_CreateWithUnstarted(&pIProcess);
    if (FAILED(ec)) return ec;

    ec = pIProcess->Start(name, args);
    if (SUCCEEDED(ec) && ppProcess) {
        *ppProcess = pIProcess;
    }
    else {
        pIProcess->Release();
    }

    return ec;
}

ELAPI _CSystem_GetAllProcesses(
    IObjectEnumerator **ppProcesses)
{
    return CPseudoKernel::System_GetAllProcesses(ppProcesses);
}

ELAPI_(IProcess *) _CProcess_GetCurrent()
{
    IProcess * pCurrentProcess = NULL;
    CPseudoKernel::Process_GetCurrent(&pCurrentProcess);
    assert(NULL != pCurrentProcess);
    pCurrentProcess->Release();
    return pCurrentProcess;
}

ELAPI_(void) _CProcess_Exit(
    ExitCode exitCode)
{
    exit(exitCode);
}

ELAPI_(void) _CProcess_Terminate(
    ExitCode exitCode)
{
    // Call thread quit routines and clean up thread static objects
    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (pContext) {
        pContext->Release();
        pContext->DoAtQuit();
        _CThread_SetLocalObject(TL_QUIT_SLOT, (PInterface)NULL);
    }

    // Call process exit routines and clean up process static objects
    s_processExitContext.DoAtExit();

    CleanUpAllThreadsLocalSlots();

    FreeCurProcComponents();
    CPseudoKernel::Process_ExitCurrent(exitCode);
    assert(0);
}

ELAPI _CProcess_AtExit(
        /* [in] */ PProcessExitRoutine pEntry,
        /* [in] */ PVoid pUserData)
{
    if (!pEntry) return E_INVALID_ARGUMENT;

    return s_processExitContext.AddExitRoutine(pEntry, pUserData);
}

ELAPI _CModule_Load(
    WString name,
    ModuleLoadFlags flags,
    IModule **ppModule)
{
    ECode ec;
    if (!ppModule || name.IsNullOrEmpty()) {
        return E_INVALID_ARGUMENT;
    }

    ec = CPseudoKernel::Process_LoadModule(name, flags, ppModule);
    if (FAILED(ec)) {
        const wchar_t *pName;
        pName = wcsrchr(name, L'/');
        if (!pName) {
            pName = name;
        }
        else {
            pName++;
        }
        ec = CPseudoKernel::Process_LoadModule(pName, flags, ppModule);
    }
    return ec;
}

ELAPI _CThread_New(
    PThreadMain pEntry,
    void *pArg,
    ThreadCreationFlags flags,
    IThread **ppThread)
{
    IThread *pThread;

    ECode ec = CPseudoKernel::Thread_Create((Address)ThreadEntry,
                                        (Address)pEntry, (Address)pArg,
                                        flags, &pThread);
    if (FAILED(ec)) {
        return ec;
	}

	IApplet *pApplet;
	ec = _CApplet_GetCurrent((PInterface *)&pApplet);
	if (SUCCEEDED(ec)) {
        IAppletSystemSpecific *pAppletSystemSpecific = IAppletSystemSpecific::Probe(pApplet);
        assert(pAppletSystemSpecific);
		pAppletSystemSpecific->NotifyThreadCreated(pThread);
		pApplet->Release();
	}

	if (NULL != ppThread) {
	    *ppThread = pThread;
	}
	else {
	    pThread->Release();
	}

    return NOERROR;
}

ELAPI _CThread_AtQuit(
            PThreadQuitRoutine pEntry,
            PVoid pUserData)
{
    if (!pEntry) return E_INVALID_ARGUMENT;

    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (!pContext) {
        pContext = new CThreadQuitContext;
        if (!pContext) {
            return E_OUT_OF_MEMORY;
        }
        pContext->AddRef();
        _CThread_SetLocalObject(TL_QUIT_SLOT, pContext);
    }
    else {
        pContext->Release();
    }

    return pContext->AddQuitRoutine(pEntry, pUserData);
}

ELAPI_(IThread *) _CThread_GetCurrent()
{
    IThread * pCurrentThread = NULL;
    CPseudoKernel::Thread_GetCurrent(&pCurrentThread);
    assert(NULL != pCurrentThread);
    pCurrentThread->Release();
    return pCurrentThread;
}

ELAPI_(void) _CThread_Quit(
    QuitCode quitCode)
{
    IApplet *pApplet;

	ECode ec = _CApplet_GetCurrent((PInterface *)&pApplet);
	IThread *pThread = _CThread_GetCurrent();
	assert(NULL != pThread);
	if (SUCCEEDED(ec)) {
        IAppletSystemSpecific *pAppletSystemSpecific = IAppletSystemSpecific::Probe(pApplet);
		pAppletSystemSpecific->NotifyThreadQuit(pThread);
		pApplet->Release();
	}

	// Call thread quit routines and clean up thread static objects
    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (pContext) {
        pContext->Release();
        pContext->DoAtQuit();
        _CThread_SetLocalObject(TL_QUIT_SLOT, (PInterface)NULL);
    }

    Boolean bIsMainThread = FALSE;
    CPseudoKernel::Thread_CurrentIsMain(&bIsMainThread);
    if (bIsMainThread) {
        // call process exit routines and clean up process static objects;
        s_processExitContext.DoAtExit();
        CleanUpAllThreadsLocalSlots();
    }
    else {
        CleanUpThreadLocalSlots();
    }
    CPseudoKernel::Thread_QuitCurrent(quitCode);
    assert(0);
}

ELAPI _CThread_Sleep(
    Millisecond32 ms,
    WaitResult *pResult)
{
    return CPseudoKernel::Thread_Sleep(ms, pResult);
}

#ifndef UINT_MAX
#define UINT_MAX    0xffffffff
#endif

ELAPI _CThread_Delay(
    Microsecond32 us)
{
    if (0 == s_uDelayLoopCount) return E_NOT_SUPPORTED;

    UInt32 uMicroseconds = (UInt32)us;
    volatile _ELASTOS Boolean bContinue = TRUE;

    volatile UInt32 u;
    volatile UInt32 uCount;
    register UInt32 uCurrentDelayMicroseconds;

    do {
        uCurrentDelayMicroseconds = UINT_MAX / s_uDelayLoopCount;
        if (uMicroseconds < uCurrentDelayMicroseconds) {
            uCurrentDelayMicroseconds = uMicroseconds;
        }

        u = 0;
        uCount = s_uDelayLoopCount * uCurrentDelayMicroseconds;

        while (bContinue && u < uCount) {
            u++;
        }

        uMicroseconds -= uCurrentDelayMicroseconds;
    } while (0 < uMicroseconds);

    return NOERROR;
}

ELAPI _CThread_Yield()
{
    return CPseudoKernel::Thread_Yield();
}

ELAPI _CVirtualMemory_Alloc(
    Address baseAddr,
    MemorySize size,
    MemoryMapFlags flags,
    MemoryProtection protect,
    Address *pBaseAddr)
{
    return CPseudoKernel::VirtualMemory_Map(baseAddr,
                                     size, flags, protect,
                                     pBaseAddr);
}

ELAPI _CVirtualMemory_Query(
    Address address,
    Address *pBaseAddr,
    MemorySize *pSize)
{
    return CPseudoKernel::VirtualMemory_Query(address, pBaseAddr, pSize);
}

ELAPI _CVirtualMemory_QueryPhysicalBlock(
    Address vAddress,
    Address *pAddress,
    MemorySize *pSize)
{
    return E_NOT_IMPLEMENTED;
}

ELAPI _CVirtualMemory_SetProtection(
    Address baseAddr,
    MemorySize size,
    MemoryProtection protect)
{
    return CPseudoKernel::VirtualMemory_SetProtection(baseAddr, size, protect);
}

ELAPI _CVirtualMemory_Commit(
    Address address)
{
    return CPseudoKernel::VirtualMemory_Commit(address);
}

ELAPI _CVirtualMemory_CheckProtection(
    Address address,
    MemoryProtection protect,
    Boolean *pIsValid)
{
    return CPseudoKernel::VirtualMemory_CheckProtection(address, protect, pIsValid);
}

ELAPI _CVirtualMemory_Free(
    Address baseAddr,
    MemorySize size)
{
    return CPseudoKernel::VirtualMemory_Unmap(baseAddr, size);
}

ELAPI _CVirtualMemory_IoRemap(
    Address virtualAddr,
    MemorySize size,
    Address physicalAddr,
    MemoryMapFlags flags,
    MemoryProtection protect,
    Address *pVirtualAddr)
{
    return CPseudoKernel::VirtualMemory_IoRemap(virtualAddr, size, physicalAddr,
                flags, protect, pVirtualAddr);
}

ELAPI _CMutex_New(
    /* [out] */ IMutex **ppMutex)
{
    return CPseudoKernel::Mutex_Create(ppMutex);
}

ELAPI _CCondition_New(
    /* [out] */ ICondition **ppCondition)
{
    return CPseudoKernel::Condition_Create(ppCondition);
}

ELAPI _CEvent_New(
    /* [in] */ Boolean manualReset,
    /* [in] */ EventState initialState,
    /* [out] */ IEvent **ppEvent)
{
    return CPseudoKernel::Event_Create(manualReset, initialState, ppEvent);
}

ELAPI _CReaderWriterLock_New(
    /* [out] */ IReaderWriterLock **ppRWLock)
{
    return CPseudoKernel::ReaderWriterLock_Create(ppRWLock);
}

ELAPI _CMutex_NewWithName(
    /* [in] */ WString name,
    /* [out] */ IMutex **ppMutex,
    /* [out] */ Boolean *pAlreadyExists)
{
    return CPseudoKernel::Mutex_Create(name, ppMutex,pAlreadyExists);
}

ELAPI _CCondition_NewWithName(
    /* [in] */ WString name,
    /* [out] */ ICondition **ppCondition,
    /* [out] */ Boolean *pAlreadyExists)
{
    return CPseudoKernel::Condition_Create(name, ppCondition,
                                              pAlreadyExists);
}

ELAPI _CEvent_NewWithName(
    /* [in] */ WString name,
    /* [in] */ Boolean manualReset,
    /* [in] */ EventState initialState,
    /* [out] */ IEvent **ppEvent,
    /* [out] */ Boolean *pAlreadyExists)
{
    return CPseudoKernel::Event_Create(name,
                                    manualReset,
                                    initialState,
                                    ppEvent,
                                    pAlreadyExists);
}

ELAPI _CReaderWriterLock_NewWithName(
    /* [in] */ WString name,
    /* [out] */ IReaderWriterLock **ppRWLock,
    /* [out] */ Boolean *pAlreadyExists)
{
    return CPseudoKernel::ReaderWriterLock_Create(name,
                                                  ppRWLock,
                                                  pAlreadyExists);
}

ELAPI _CSharedMemory_New(
    /* [in] */ WString name,
    /* [in] */ MemorySize size,
    /* [in] */ Boolean reserved,
    /* [out] */ ISharedMemory **ppSharedMemory,
    /* [out] */ Boolean *pAlreadyExists)
{
    if (!reserved) return E_INVALID_ARGUMENT;

    if (NULL == ppSharedMemory) return E_INVALID_ARGUMENT;

    return CPseudoKernel::SharedMemory_Create(name, size, reserved,
                                          ppSharedMemory,
                                          pAlreadyExists);
}

ELAPI _CSystem_CreateSystemEventHandle(
    /* [in] */ SystemEvents interestedEvents, IEvent **ppEvent)
{
    return CPseudoKernel::System_RequestIntrestedEvent(interestedEvents, ppEvent);
}

ELAPI _CHostingManager_Acquire(
    /* [out] */ IHostingManager **ppHostingManager)
{
    return CPseudoKernel::System_GetHostingManager(ppHostingManager);
}

// TODO: Optimized it
//
ELAPI _CSystem_WaitForAnySystemEvent(
    /* [in] */ SystemEvents interestedEvents, SystemEvent *pSystemEvent)
{
    WaitResult wr;
    ECode ec;
    IEvent *pSysEvent;

    ec = CPseudoKernel::System_RequestIntrestedEvent(interestedEvents, &pSysEvent);
    if (FAILED(ec)) return ec;

    do {
        ec = pSysEvent->Wait(&wr, (EventState *)pSystemEvent);
    } while (FAILED(ec));

    pSysEvent->Release();
    return ec;
}

ELAPI _CCriticalSection_Initialize(
    /* [in] */ CriticalSection *pCriticalSection)
{
    assert(pCriticalSection);

    return ((_CCriticalSection *)pCriticalSection)->Initialize();
}

ELAPI_(void) _CCriticalSection_Enter(
    /* [in] */ CriticalSection *pCriticalSection)
{
    assert(pCriticalSection);

    ((_CCriticalSection *)pCriticalSection)->Enter();
}

ELAPI _CCriticalSection_TryEnter(
    /* [in] */ CriticalSection *pCriticalSection,
    /* [out] */ Boolean *pEntered)
{
    assert(pCriticalSection);

    return ((_CCriticalSection *)pCriticalSection)->TryEnter(pEntered);
}

ELAPI_(void) _CCriticalSection_Leave(
    /* [in] */ CriticalSection *pCriticalSection)
{
    assert(pCriticalSection);

    ((_CCriticalSection *)pCriticalSection)->Leave();
}

ELAPI_(void) _CCriticalSection_Terminate(
    /* [in] */ CriticalSection *pCriticalSection)
{
    assert(pCriticalSection);

    ((_CCriticalSection *)pCriticalSection)->Terminate();
}

EXTERN void InitTLS()
{
    _CCriticalSection_Initialize(&g_tlsLock);
    memset(g_tlsTypes, ThreadLocalSlotType_Free, TLS_TOTAL_SLOTS);
    g_tlsAllocatedList.Initialize();

    g_tlsTypes[TL_SEQUENCED_SLOT] = ThreadLocalSlotType_Value;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_SEQUENCED_SLOT]);

    g_tlsTypes[TL_QUIT_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_QUIT_SLOT]);

    g_tlsTypes[TL_DOMAIN_SLOT] = ThreadLocalSlotType_Value;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_DOMAIN_SLOT]);

    g_tlsTypes[TL_CALLBACK_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_CALLBACK_SLOT]);

    g_tlsTypes[TL_HELPER_INFO_SLOT] = ThreadLocalSlotType_Value;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_HELPER_INFO_SLOT]);

    g_tlsTypes[TL_APPLET_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_APPLET_SLOT]);

    g_tlsTypes[TL_ORG_CALLBACK_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_ORG_CALLBACK_SLOT]);

    g_tlsTypes[TL_APPLET_DIR_SLOT] = ThreadLocalSlotType_Value;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_APPLET_DIR_SLOT]);
}

EXTERN void UninitTLS()
{
    _CCriticalSection_Terminate(&g_tlsLock);
}

ELAPI _CThread_AcquireLocalSlot(
    /* [in]  */ ThreadLocalSlotType slotType,
    /* [out] */ Int32 *pSlotIndex)
{
    ECode ec = NOERROR;

    _CCriticalSection_Enter(&g_tlsLock);
    ec = CPseudoKernel::Tls_AcquireSlot(slotType, pSlotIndex);
    if (FAILED(ec)) {
        _CCriticalSection_Leave(&g_tlsLock);
        return ec;
    }

    g_tlsTypes[*pSlotIndex] = slotType;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[*pSlotIndex]);

    _CCriticalSection_Leave(&g_tlsLock);

    return ec;
}

ELAPI _CThread_RelinquishLocalSlot(
    /* [in] */ Address slotIndex)
{
    BufferOf_<Address, THREAD_MINIMUM_AVAILABLE> eaUsedPtrs;
    ECode ec = NOERROR;
    Byte tlsType;
    Int32 i, used;

    _CCriticalSection_Enter(&g_tlsLock);
    ec = CPseudoKernel::Tls_RelinquishSlot(slotIndex, &eaUsedPtrs);
    if (FAILED(ec)) {
        _CCriticalSection_Leave(&g_tlsLock);
        return ec;
    }

    tlsType = g_tlsTypes[slotIndex];
    g_tlsTypes[slotIndex] = ThreadLocalSlotType_Free;
    g_tlsAllocatedNodes[slotIndex].Detach();

    _CCriticalSection_Leave(&g_tlsLock);

    used = eaUsedPtrs.GetUsed();
    if (ThreadLocalSlotType_Mem == tlsType) {
        for (i = 0; i < used; i++) {
            if (NULL != eaUsedPtrs[i]) free((PVoid)eaUsedPtrs[i]);
        }
    }
    else if (ThreadLocalSlotType_Obj == tlsType) {
        for (i = 0; i < used; i++) {
            if (NULL != eaUsedPtrs[i]) {
                ((PInterface)(PVoid)eaUsedPtrs[i])->Release();
            }
        }
    }

    return NOERROR;
}

ELAPI _CThread_SetLocalValue(
    /* [in] */ Int32 slotIndex,
    /* [in] */ TLValue value)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS) {
        return E_INVALID_ARGUMENT;
    }
    return CPseudoKernel::Tls_SetValue(
                            ThreadLocalSlotType_Value,
                            slotIndex, value);
}

ELAPI _CThread_SetLocalMemory(
    /* [in] */ Int32 slotIndex,
    /* [in] */ PVoid pMem)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS) {
        return E_INVALID_ARGUMENT;
    }
    return CPseudoKernel::Tls_SetValue(
                            ThreadLocalSlotType_Mem,
                            slotIndex, pMem);
}

ELAPI _CThread_SetLocalObject(
    /* [in] */ Int32 slotIndex,
    /* [in] */ PInterface pObj)
{
    ECode ec = NOERROR;
    PInterface pObject = NULL;
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS) {
        return E_INVALID_ARGUMENT;
    }
    ec = CPseudoKernel::Tls_GetValue(
                                ThreadLocalSlotType_Obj,
                                slotIndex, (PVoid *)&pObject);
    if (pObject) pObject->Release();
    return CPseudoKernel::Tls_SetValue(
                            ThreadLocalSlotType_Obj,
                            slotIndex, (PVoid)pObj);
}

ELAPI _CThread_GetLocalValue(
    /* [in] */ Int32 slotIndex,
    /* [out] */ TLValue *pValue)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS) {
        return E_INVALID_ARGUMENT;
    }
    return CPseudoKernel::Tls_GetValue(
                            ThreadLocalSlotType_Value,
                            slotIndex, pValue);
}

ELAPI _CThread_GetLocalMemory(
    /* [in] */ Int32 slotIndex,
    /* [out] */ PVoid *ppMem)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS) {
        return E_INVALID_ARGUMENT;
    }
    return CPseudoKernel::Tls_GetValue(
                                ThreadLocalSlotType_Mem,
                                slotIndex, ppMem);
}

ELAPI _CThread_GetLocalObject(
    /* [in] */ Int32 slotIndex,
    /* [out] */ PInterface *ppObj)
{
    ECode ec = NOERROR;
    PVoid pObject = NULL;

    if ((NULL == ppObj)
        || (slotIndex < 0)
        || (slotIndex >= TLS_TOTAL_SLOTS)) {
        return E_INVALID_ARGUMENT;
    }
    ec = CPseudoKernel::Tls_GetValue(
                                ThreadLocalSlotType_Obj,
                                slotIndex, &pObject);
    if (FAILED(ec)) {
        return ec;
    }
    *ppObj = (PInterface)pObject;
    if (NULL != *ppObj) {
        (*ppObj)->AddRef();
    }
    return ec;
}

EXTERN void CleanUpThreadLocalSlots()
{
    DLinkNode *pNode = NULL;
    PVoid pValue = NULL;
    ECode ec = NOERROR;
    PVoid tlsValues[TLS_TOTAL_SLOTS];
    Byte tlsTypes[TLS_TOTAL_SLOTS];
    Int32 i, used = 0;

    _CCriticalSection_Enter(&g_tlsLock);

    ForEachDLinkNode(DLinkNode *, pNode, &g_tlsAllocatedList) {
        i = pNode - g_tlsAllocatedNodes;
        if (ThreadLocalSlotType_Mem == g_tlsTypes[i]
            || ThreadLocalSlotType_Obj == g_tlsTypes[i]) {
            ec = CPseudoKernel::Tls_GetValue(g_tlsTypes[i], i, &pValue);
            if (SUCCEEDED(ec) && (NULL != pValue)) {
                tlsValues[used] = pValue;
                tlsTypes[used] = g_tlsTypes[i];
                used++;
            }
        }
    }

    _CCriticalSection_Leave(&g_tlsLock);

    for (i = 0; i < used; i++) {
        if (ThreadLocalSlotType_Mem == tlsTypes[i]) {
            free(tlsValues[i]);
        }
        else {
            ((PInterface)tlsValues[i])->Release();
        }
    }

    return ;
}

static void CleanUpAllThreadsLocalSlots()
{
    BufferOf_<Address, THREAD_MINIMUM_AVAILABLE> eaUsedPtrs;
    BufferOf_<Int32, TLS_TOTAL_SLOTS> eaUsedIndices;
    Byte tlsType;
    Int32 i, j, nIndicesUsed, nPtrsUsed, index;
    ECode ec;
    DLinkNode * pNode = NULL;

    _CCriticalSection_Enter(&g_tlsLock);

    ForEachDLinkNode(DLinkNode*, pNode, &g_tlsAllocatedList) {
        eaUsedIndices.Append(pNode - g_tlsAllocatedNodes);
    }

    _CCriticalSection_Leave(&g_tlsLock);

    nIndicesUsed = eaUsedIndices.GetUsed();
    for (i = 0; i < nIndicesUsed; i++) {
        _CCriticalSection_Enter(&g_tlsLock);

        index = eaUsedIndices[i];
        tlsType = g_tlsTypes[index];
        ec = CPseudoKernel::Tls_CleanupSlot(index, &eaUsedPtrs);

        _CCriticalSection_Leave(&g_tlsLock);

        if (FAILED(ec)) {
            continue;
        }

        nPtrsUsed = eaUsedPtrs.GetUsed();
        if (ThreadLocalSlotType_Mem == tlsType) {
            for (j = 0; j < nPtrsUsed; j++) {
                if (NULL != eaUsedPtrs[j]) free((PVoid)eaUsedPtrs[j]);
            }
        }
        else if (ThreadLocalSlotType_Obj == tlsType) {
            for (j = 0; j < nPtrsUsed; j++) {
                if (NULL != eaUsedPtrs[j]) {
                    ((PInterface)(PVoid)eaUsedPtrs[j])->Release();
                }
            }
        }
    }

    return ;
}

EXTERN_C ECode Reply(
    Aura_ChannelId id, void *pvOutBuf, size_t uOutBufSize, _ELASTOS Boolean bCleanupTLSlots)
{

    // Call thread quit routines and clean up thread static objects
    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (pContext) {
        pContext->Release();
        pContext->DoAtQuit();
        _CThread_SetLocalObject(TL_QUIT_SLOT, (PInterface)NULL);
    }

    if (bCleanupTLSlots) {
        CleanUpThreadLocalSlots();
    }
    return CPseudoSyscall::SysReply(id, pvOutBuf, uOutBufSize);
}

ELAPI _CEvent_WaitForAnyEvents(
    /* [in] */ const BufferOf<IEvent *> *events,
    /* [out] */ WaitResult *pResult,
    /* [out] */ Int32 *pIndex,
    /* [out] */ EventState *pState)
{
    return CPseudoKernel::System_TryWaitForAnyEvents(
                             events, INFINITE, pResult, pIndex, pState);
}

ELAPI _CEvent_TryWaitForAnyEvents(
    /* [in] */ const BufferOf<IEvent *> * events,
    /* [in] */ Millisecond32 timeout,
    /* [out] */ WaitResult *pResult,
    /* [out] */ Int32 *pIndex,
    /* [out] */ EventState *pState)
{
    return CPseudoKernel::System_TryWaitForAnyEvents(
                events, timeout, pResult, pIndex, pState);
}

ELAPI _CProcess_FlushInstructionCache(
    /* [in] */ Address baseAddr,
    /* [in] */ MemorySize size)
{
    return CPseudoKernel::Process_FlushInstructionCache(baseAddr, size);
}

ELAPI _Impl_GetStartInfo(
    WStringBuf * esbCmdName,
    WStringBuf * esbCmdArgs)
{
    if ((NULL == esbCmdName) || !esbCmdName->GetCapacity()) {
        return E_INVALID_ARGUMENT;
    }

    return _CProcess_GetCurrent()->GetStartInfo(esbCmdName, esbCmdArgs);
}

ELAPI  _EzGetEnvironmentMutex(
    IMutex **ppEnvMutex)
{
    return CPseudoKernel::System_GetEnvironmentMutex(ppEnvMutex);
}

ELAPI  _EzGetEnvBase(
    wchar_t ***pppwszEnvBase, wchar_t **ppwszDevpath)
{
    _GetEnvBase(pppwszEnvBase, ppwszDevpath);
    return NOERROR;
}

//
// REDIRECT_INFO_BASE is defined in \elastos\inc\elacfg.h
//
#define REDIRECT_ELEMENT_SIZE       512         //0.5KB

ELAPI _EzSetStdDevice(UInt32 stdDeviceNo, WString fileName)
{
    return E_NOT_IMPLEMENTED;
}

ELAPI _EzGetStdDevice(UInt32 stdDeviceNo, WChar ** ppFileName)
{
    return E_NOT_IMPLEMENTED;
}

static Void SetErrorInfo(CONST Void * pBuf, UInt32 size, UInt32 width)
{
    return ;
}

ELAPI_(PVoid) GetErrorInfo()
{
    return NULL;
}

ELAPI_(WString) _CErrorReport_GetWString()
{
    return (const wchar_t *)GetErrorInfo();
}

ELAPI_(AString) _CErrorReport_GetAString()
{
    return (const char *)GetErrorInfo();
}

ELAPI_(AString) _CErrorReport_GetUrl()
{
    return (char *)GetErrorInfo();
}

ELAPI _CErrorReport_SetWString(
    /* [in] */ WString string)
{
    if (string.IsNull()) string = L"";

    SetErrorInfo(string, wcslen(string), sizeof(WChar));

    return E_ERROR_STRING;
}

ELAPI _CErrorReport_SetAString(
    /* [in] */ AString string)
{
    if (string.IsNull()) string = "";

    SetErrorInfo(string, strlen(string), sizeof(AChar));

    return E_ERROR_STRING_A;
}

ELAPI _CErrorReport_SetUrl(
    /* [in] */ AString url)
{
    if (url.IsNull()) url = "";

    SetErrorInfo(url, strlen(url), sizeof(AChar));

    return E_ERROR_URL;
}

ELAPI _EzGetTickCount(/*Out*/unsigned long *pCount)
{
    return E_NOT_IMPLEMENTED;
}

ELAPI _CObject_ReleaseAtProcessExit(PInterface pObject)
{
    if (!pObject) return E_INVALID_ARGUMENT;

    return s_processExitContext.AddObject(pObject);
}

ELAPI _CObject_ReleaseAtThreadQuit(
    /* [in] */ PInterface pObject)
{
    if (!pObject) return E_INVALID_ARGUMENT;

    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (!pContext) {
        pContext = new CThreadQuitContext;
        if (!pContext) {
            return E_OUT_OF_MEMORY;
        }
        pContext->AddRef();
        _CThread_SetLocalObject(TL_QUIT_SLOT, pContext);
    }
    else {
        pContext->Release();
    }

    return pContext->AddObject(pObject);
}

ELAPI _CObject_ReleaseAtAppletFinish(
    /* [in] */ PInterface pObject)
{
    ECode ec;
    PInterface pAppletContext = NULL;
    if (!pObject) return E_INVALID_ARGUMENT;

    ec = _Impl_CAppletContext_GetCurrent(&pAppletContext);
    if (FAILED(ec) && E_NOT_IN_ANY_APPLET != ec) return ec;

    if (pAppletContext) pAppletContext->Release();
    else return _CObject_ReleaseAtProcessExit(pObject);

    return ((CAppletContext*)pAppletContext)->AddObject(pObject);
}

ELAPI _CObject_EnterContext(PInterface pObject, PContext pContext)
{
    return pContext->Aggregate(AggrType_ObjectEnter, pObject);
}

ELAPI _CObject_LeaveContext(PInterface pObject, PContext pContext)
{
    return pContext->Aggregate(AggrType_ObjectLeave, pObject);
}

ELAPI_(Boolean) _Impl_CheckHelperInfoFlag(Flags32 flag)
{
    Flags32 uFlag = 0;
    ECode ec;

    ec = _CThread_GetLocalValue(TL_HELPER_INFO_SLOT, (TLValue*)&uFlag);
    assert(SUCCEEDED(ec));

    if (uFlag & flag) return TRUE;
    else return FALSE;
}

ELAPI_(void) _Impl_SetHelperInfoFlag(Flags32 flag, Boolean bValue)
{
    Flags32 uFlag = 0;
    ECode ec;

    ec = _CThread_GetLocalValue(TL_HELPER_INFO_SLOT, (TLValue*)&uFlag);
    assert(SUCCEEDED(ec));

    if (bValue) {
        uFlag |= flag;
    }
    else {
        uFlag &= ~flag;
    }

    ec = _CThread_SetLocalValue(TL_HELPER_INFO_SLOT, (TLValue)uFlag);
    assert(SUCCEEDED(ec));
}

ELAPI _Impl_EnterProtectedZone()
{
    _Impl_SetHelperInfoFlag(HELPER_ENTERED_PROTECTED_ZONE, TRUE);
    return NOERROR;
}

ELAPI _Impl_LeaveProtectedZone()
{
    _Impl_SetHelperInfoFlag(HELPER_ENTERED_PROTECTED_ZONE, FALSE);
    return NOERROR;
}

ELAPI _Impl_InsideProtectedZone()
{
    if (!_Impl_CheckHelperInfoFlag(HELPER_ENTERED_PROTECTED_ZONE)) {
        return E_NOT_IN_PROTECTED_ZONE;
    }

    return NOERROR;
}

ELAPI_(void *) _Elastos_CriticalSection_Enter(
        /* [in] */ CRITICAL_SECTION *pCriticalSection)
{
    _CCriticalSection_Enter(pCriticalSection);

    return NULL;
}

ELAPI_(void) _Elastos_CriticalSection_Leave(
        /* [in] */ CRITICAL_SECTION *pCriticalSection,
        /* [in] */ void *pContext)
{
    _CCriticalSection_Leave(pCriticalSection);
}

ELAPI_(_CMapNode*) _Impl_CMap_AllocNode(WString key, WString value)
{
    Int32 nKeyLen = (key.GetLength() + 1) * sizeof(WChar);
    Int32 nValueLen = (value.GetLength() + 1) * sizeof(WChar);
    Int32 nSize = sizeof(_CMapNode) + nKeyLen + nValueLen;

    PByte pBuf = new Byte[nSize];
    if (pBuf == NULL) return NULL;

    _CMapNode* pNode = (_CMapNode*) new (pBuf) _CMapNode;

    pNode->m_pwcsKey = (WChar*)(pBuf + sizeof(_CMapNode));
    pNode->m_pwcsValue =(WChar*)(pBuf + sizeof(_CMapNode) + nKeyLen);

    wcscpy(pNode->m_pwcsKey, key);
    wcscpy(pNode->m_pwcsValue, value);

    return pNode;
}

ELAPI_(void) _Impl_CMap_FreeNode(_CMapNode* pNode)
{
    delete [] (PByte) pNode;
}
